package cn.bitkit.component.redis;

import cn.bitkit.base.exception.BusinessException;
import cn.bitkit.component.context.SpringContext;
import cn.bitkit.component.id.ULID;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author changbo
 */
public class WorkIdHandler {

    private String type = BasicRedisKey.BASIC_WORK_ID;
    private final String RANDOM_ID = ULID.getId();
    private final int EXPIRE_TIME = 10;
    private final ExecutorService VT_EXECUTOR = Executors.newVirtualThreadPerTaskExecutor();
    private static WorkIdHandler handler;

    public static WorkIdHandler getInstance(){
        if(handler == null){
            handler = getInstance(BasicRedisKey.BASIC_WORK_ID);
        }
        return handler;
    }

    public static WorkIdHandler getInstance(String type){
        WorkIdHandler handler = new WorkIdHandler();
        handler.type = type;
        return handler;
    }

    /**
     * 获取机器id
     * @param max 最大id
     * @return 机器id
     */
    public int getWorkId(int max) {
        StringRedisTemplate stringRedisTemplate = SpringContext.getAssertedBean(StringRedisTemplate.class);
        for (int i = 0; i < max; i++){
            Boolean res = stringRedisTemplate.opsForValue().setIfAbsent(type + i, RANDOM_ID, Duration.ofMinutes(EXPIRE_TIME));
            if (Boolean.TRUE.equals(res)) {
                addTimer(i);
                return i;
            }
        }
        throw new BusinessException("获取机器id失败:无空闲id");
    }

    /**
     * 定时续期
     * @param workId 机器id
     */
    private void addTimer(int workId){
        VT_EXECUTOR.submit(() -> {
            while (true) {
                Thread.sleep(EXPIRE_TIME/2 * 1000);
                StringRedisTemplate stringRedisTemplate = SpringContext.getAssertedBean(StringRedisTemplate.class);
                stringRedisTemplate.opsForValue().set(BasicRedisKey.BASIC_WORK_ID + workId, RANDOM_ID, Duration.ofMinutes(EXPIRE_TIME));
            }
        });
    }

    public void releaseWorkId(int workId){
        VT_EXECUTOR.shutdownNow();
        StringRedisTemplate stringRedisTemplate = SpringContext.getAssertedBean(StringRedisTemplate.class);
        stringRedisTemplate.delete(BasicRedisKey.BASIC_WORK_ID + workId);
    }

}
